/**
 * 快速排序中间函数
 */
const SORT_ARRAY = <T>(ary: Array<T>, compareFunc: ICompareFunction<T>, lo: number, hi: number) => {
    let i = lo, j = hi;
    let x = ary[Math.ceil((lo + hi) / 2)];
    do {
        while (compareFunc(ary[i], x))
            i++;
        while (compareFunc(x, ary[j]))
            j--;
        if (i <= j) {
            let tmp = ary[i];
            ary[i] = ary[j];
            ary[j] = tmp;
            i++;
            j--;
        }
    } while (i <= j);
    if (lo < j)
        SORT_ARRAY(ary, compareFunc, lo, j);
    if (i < hi)
        SORT_ARRAY(ary, compareFunc, i, hi);
};

/**
 * 默认排序对比函数(升序)
 */
const COMPARE_VALUE_INCREASE = (a: number, b: number): boolean => {
    return a < b;
};

/**
 * 比较函数接口
 */
interface ICompareFunction<T> {
    (a: T, b: T): boolean
}

/**
 * 松散对象接口
 */
interface ILoose<T> {
    [key: string]: T;
}

/**
 * 类型化数组类型
 */
type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array;

let _idCounter = 0;

/**
 * 通用方法
 */
class Utils {

    /**
     * 获取字符串字节长度
     * @param str 字符串
     * @returns 字节数
     */
    public static byteLength(str: string): number {
        let byteLength = 0;
        if (str === undefined || str.length === 0) return 0;
        for (let i = 0; i < str.length; i++) {
            if (str.charCodeAt(i) > 255) {
                byteLength += 2;
            } else {
                byteLength++;
            }
        }
        return byteLength;
    }

    /**
     * 无序数组是否相等
     * @param a 数组
     * @param b 数组
     * @param equalCompare 元素相等对比函数
     * @returns 是否相等
     */
    public static disorderedArrayEqual(a: any[], b: any[], equalCompare?: ICompareFunction<any>): boolean {
        if (a.length !== b.length) return false;
        for (let i = 0; i < a.length; i++) {
            const idx = b.findIndex(vb => equalCompare ? equalCompare(a[i], vb) : a[i] === vb);
            if (idx < 0) return false;
        }
        return true;
    }

    /**
     * 滤除字符串多余的空格（滤除开头和结尾，以及多于1个的连续的空格）
     * @param text 字符串
     * @returns 处理完的字符串
     */
    public static filterSpace(text: string): string {
        const V_ARRAY: string[] = [];
        let count = 0;
        for (let s of text) {
            if (s === ' ') {
                if (count === 0) {
                    V_ARRAY.push(s);
                }
                count++;
            } else {
                V_ARRAY.push(s);
                count = 0;
            }
        }
        if (V_ARRAY[0] === ' ') V_ARRAY.splice(0, 1);
        if (V_ARRAY[V_ARRAY.length - 1] === ' ') V_ARRAY.splice(V_ARRAY.length - 1, 1);
        return V_ARRAY.join('');
    }

    /**
     * 为字符串添加格式（缩进和分行）
     * @param text 字符串
     * @param rowLength 行长度（一个英文字符长1，一个汉字字符长2）
     * @param paragraph 首行缩进量（一个英文字符长2，一个汉字字符长4）
     * @returns 添加完格式的字符串
     */
    public static formatText(text: string, rowLength: number, paragraph: number): string {
        let txt = '';
        let len = 0;
        if (paragraph) {
            for (let i = 0; i < paragraph; i++) {
                txt += '\t';
            }
            len = paragraph * 0.5;
        }
        for (let i = 0; i < text.length; i++) {
            const c = text[i];
            len += text.charCodeAt(i) > 255 ? 2 : 1;
            if (len + 1.9 > rowLength) {
                txt += c + '\n';
                len = 0;
            } else {
                txt += c;
            }
        }
        return txt;
    }

    /**
     * 获取全局计数
     * @returns 当前计数
     */
    public static get id(): number {
        return ++_idCounter;
    }

    /**
     * 判断是否为PC端
     * @returns 是否PC端
     */
    public static isPC(): boolean {
        return !('ontouchstart' in document.documentElement);
    }

    /**
     * 单位化数字
     * @param number 数值 {number}
     * @param unit 单位 {number}
     * @returns normalizedNumber 单位化的数值 {number}
     */
    public static normalizeNumber(number: number, unit: number = 0.02): string {
        const temp = unit.toString();
        const l = temp.length;
        let dl = temp.indexOf(".");
        dl = dl === -1 ? 0 : dl;
        const fl = dl === 0 ? 0 : l - dl - 1;
        const count = Math.round(number / unit) * unit;
        return count.toFixed(fl);
    }

    /**
     * 移除集合的重复值
     * @param items 集合
     * @param compare 对比函数
     * @returns 无重复值的集合
     */
    public static noDuplication(items: Array<any>, compare?: ICompareFunction<any>): any[] {
        for (const item of items) {
            let count = 0;
            for (let i = 0; i < items.length; i++) {
                if (compare ? compare(item, items[i]) : (item === items[i])) count++;
                if (count > 1) {
                    items.splice(i, 1);
                    i--;
                }
            }
        }
        return items;
    }

    /**
     * 快速排序
     * @param ary 集合 {ArrayLike} 
     * @param compareFunc 大小比较函数([a>b -> true]为降序,[a<b -> true]为升序)
     */
    public static quickSort(ary: ArrayLike<any>, compareFunc: ICompareFunction<any> = COMPARE_VALUE_INCREASE): void {
        if (ary.length > 1) {
            SORT_ARRAY(ary as Array<any>, compareFunc, 0, ary.length - 1);
        }
    }

    /**
     * 休眠(毫秒)
     * @param ms 毫秒数
     */
    public static async sleep(ms: number): Promise<unknown> {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    /**
     * 按序排列索引
     * @param ary 目标序列
     * @param compareFunc 对比函数
     * @param out 排序结果
     * @returns 排序结果
     */
    public static sortIndexArray(ary: Array<any>, compareFunc: ICompareFunction<any> = COMPARE_VALUE_INCREASE, result?: Array<number> | TypedArray): Array<number> | TypedArray {
        const iAry = result || new Uint16Array(ary.length);
        for (let i = 0; i < ary.length; i++) {
            iAry[i] = i;
        }
        const compare = (a: any, b: any) => {
            return compareFunc(ary[a], ary[b]);
        };
        Utils.quickSort(iAry, compare);
        return iAry;
    }
}

export { Utils };
export type { ILoose, ICompareFunction, TypedArray };